-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[clang-doc] serialize friends #146165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang-doc] serialize friends #146165
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, modulo formatting and 1 small suggestion.
bf66a99
to
111fe87
Compare
a373ecb
to
8dd16ca
Compare
@llvm/pr-subscribers-clang-tools-extra Author: Erick Velez (evelez7) ChangesPatch is 24.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/146165.diff 13 Files Affected:
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index fd6f40cff1a4e..2cbf8bf6b2879 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -94,6 +94,7 @@ static llvm::Error decodeRecord(const Record &R, InfoType &Field,
case InfoType::IT_typedef:
case InfoType::IT_concept:
case InfoType::IT_variable:
+ case InfoType::IT_friend:
Field = IT;
return llvm::Error::success();
}
@@ -111,6 +112,7 @@ static llvm::Error decodeRecord(const Record &R, FieldId &Field,
case FieldId::F_child_namespace:
case FieldId::F_child_record:
case FieldId::F_concept:
+ case FieldId::F_friend:
case FieldId::F_default:
Field = F;
return llvm::Error::success();
@@ -450,6 +452,15 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
}
}
+static llvm::Error parseRecord(const Record &R, unsigned ID, StringRef Blob,
+ FriendInfo *F) {
+ if (ID == FRIEND_IS_CLASS) {
+ return decodeRecord(R, F->IsClass, Blob);
+ }
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "invalid field for Friend");
+}
+
template <typename T> static llvm::Expected<CommentInfo *> getCommentInfo(T I) {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"invalid type cannot contain CommentInfo");
@@ -525,6 +536,18 @@ template <> llvm::Error addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) {
return llvm::Error::success();
}
+template <> llvm::Error addTypeInfo(FriendInfo *I, FieldTypeInfo &&T) {
+ if (!I->Params)
+ I->Params.emplace();
+ I->Params->emplace_back(std::move(T));
+ return llvm::Error::success();
+}
+
+template <> llvm::Error addTypeInfo(FriendInfo *I, TypeInfo &&T) {
+ I->ReturnType.emplace(std::move(T));
+ return llvm::Error::success();
+}
+
template <> llvm::Error addTypeInfo(EnumInfo *I, TypeInfo &&T) {
I->BaseType = std::move(T);
return llvm::Error::success();
@@ -667,6 +690,16 @@ llvm::Error addReference(ConstraintInfo *I, Reference &&R, FieldId F) {
"ConstraintInfo cannot contain this Reference");
}
+template <>
+llvm::Error addReference(FriendInfo *Friend, Reference &&R, FieldId F) {
+ if (F == FieldId::F_friend) {
+ Friend->Ref = std::move(R);
+ return llvm::Error::success();
+ }
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Friend cannot contain this Reference");
+}
+
template <typename T, typename ChildInfoType>
static void addChild(T I, ChildInfoType &&R) {
llvm::errs() << "invalid child type for info";
@@ -700,6 +733,9 @@ template <> void addChild(RecordInfo *I, EnumInfo &&R) {
template <> void addChild(RecordInfo *I, TypedefInfo &&R) {
I->Children.Typedefs.emplace_back(std::move(R));
}
+template <> void addChild(RecordInfo *I, FriendInfo &&R) {
+ I->Friends.emplace_back(std::move(R));
+}
// Other types of children:
template <> void addChild(EnumInfo *I, EnumValueInfo &&R) {
@@ -741,6 +777,9 @@ template <> void addTemplate(FunctionInfo *I, TemplateInfo &&P) {
template <> void addTemplate(ConceptInfo *I, TemplateInfo &&P) {
I->Template = std::move(P);
}
+template <> void addTemplate(FriendInfo *I, TemplateInfo &&P) {
+ I->Template.emplace(std::move(P));
+}
// Template specializations go only into template records.
template <typename T>
@@ -921,6 +960,10 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
case BI_VAR_BLOCK_ID: {
return handleSubBlock<VarInfo>(ID, I, CreateAddFunc(addChild<T, VarInfo>));
}
+ case BI_FRIEND_BLOCK_ID: {
+ return handleSubBlock<FriendInfo>(ID, I,
+ CreateAddFunc(addChild<T, FriendInfo>));
+ }
default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"invalid subblock type");
@@ -1032,6 +1075,8 @@ ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
return createInfo<FunctionInfo>(ID);
case BI_VAR_BLOCK_ID:
return createInfo<VarInfo>(ID);
+ case BI_FRIEND_BLOCK_ID:
+ return createInfo<FriendInfo>(ID);
default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"cannot create info");
@@ -1072,6 +1117,7 @@ ClangDocBitcodeReader::readBitcode() {
case BI_TYPEDEF_BLOCK_ID:
case BI_CONCEPT_BLOCK_ID:
case BI_VAR_BLOCK_ID:
+ case BI_FRIEND_BLOCK_ID:
case BI_FUNCTION_BLOCK_ID: {
auto InfoOrErr = readBlockToInfo(ID);
if (!InfoOrErr)
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index 006ddda1b75e7..3cc0d4ad332f0 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -131,7 +131,8 @@ static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
{BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"},
{BI_CONSTRAINT_BLOCK_ID, "ConstraintBlock"},
{BI_CONCEPT_BLOCK_ID, "ConceptBlock"},
- {BI_VAR_BLOCK_ID, "VarBlock"}};
+ {BI_VAR_BLOCK_ID, "VarBlock"},
+ {BI_FRIEND_BLOCK_ID, "FriendBlock"}};
assert(Inits.size() == BlockIdCount);
for (const auto &Init : Inits)
BlockIdNameMap[Init.first] = Init.second;
@@ -224,7 +225,8 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
{VAR_USR, {"USR", &genSymbolIdAbbrev}},
{VAR_NAME, {"Name", &genStringAbbrev}},
{VAR_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
- {VAR_IS_STATIC, {"IsStatic", &genBoolAbbrev}}};
+ {VAR_IS_STATIC, {"IsStatic", &genBoolAbbrev}},
+ {FRIEND_IS_CLASS, {"IsClass", &genBoolAbbrev}}};
assert(Inits.size() == RecordIdCount);
for (const auto &Init : Inits) {
@@ -293,7 +295,8 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
CONCEPT_CONSTRAINT_EXPRESSION}},
// Constraint Block
{BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}},
- {BI_VAR_BLOCK_ID, {VAR_NAME, VAR_USR, VAR_DEFLOCATION, VAR_IS_STATIC}}};
+ {BI_VAR_BLOCK_ID, {VAR_NAME, VAR_USR, VAR_DEFLOCATION, VAR_IS_STATIC}},
+ {BI_FRIEND_BLOCK_ID, {FRIEND_IS_CLASS}}};
// AbbreviationMap
@@ -476,6 +479,19 @@ void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
emitRecord((unsigned)Field, REFERENCE_FIELD);
}
+void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) {
+ StreamSubBlockGuard Block(Stream, BI_FRIEND_BLOCK_ID);
+ emitBlock(R.Ref, FieldId::F_friend);
+ emitRecord(R.IsClass, FRIEND_IS_CLASS);
+ if (R.Template)
+ emitBlock(*R.Template);
+ if (R.Params)
+ for (const auto &P : *R.Params)
+ emitBlock(P);
+ if (R.ReturnType)
+ emitBlock(*R.ReturnType);
+}
+
void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
emitBlock(T.Type, FieldId::F_type);
@@ -628,6 +644,8 @@ void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
emitBlock(C);
if (I.Template)
emitBlock(*I.Template);
+ for (const auto &C : I.Friends)
+ emitBlock(C);
}
void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {
@@ -744,6 +762,9 @@ bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
case InfoType::IT_variable:
emitBlock(*static_cast<VarInfo *>(I));
break;
+ case InfoType::IT_friend:
+ emitBlock(*static_cast<FriendInfo *>(I));
+ break;
case InfoType::IT_default:
llvm::errs() << "Unexpected info, unable to write.\n";
return true;
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h
index f1325094f957a..d09ec4ca34006 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.h
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -70,6 +70,7 @@ enum BlockId {
BI_TYPEDEF_BLOCK_ID,
BI_CONCEPT_BLOCK_ID,
BI_VAR_BLOCK_ID,
+ BI_FRIEND_BLOCK_ID,
BI_LAST,
BI_FIRST = BI_VERSION_BLOCK_ID
};
@@ -153,6 +154,7 @@ enum RecordId {
VAR_NAME,
VAR_DEFLOCATION,
VAR_IS_STATIC,
+ FRIEND_IS_CLASS,
RI_LAST,
RI_FIRST = VERSION
};
@@ -169,7 +171,8 @@ enum class FieldId {
F_type,
F_child_namespace,
F_child_record,
- F_concept
+ F_concept,
+ F_friend
};
class ClangDocBitcodeWriter {
@@ -201,6 +204,7 @@ class ClangDocBitcodeWriter {
void emitBlock(const ConceptInfo &T);
void emitBlock(const ConstraintInfo &T);
void emitBlock(const Reference &B, FieldId F);
+ void emitBlock(const FriendInfo &R);
void emitBlock(const VarInfo &B);
private:
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index c4303d287da9e..8294ff9118558 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -987,6 +987,7 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
break;
case InfoType::IT_concept:
case InfoType::IT_variable:
+ case InfoType::IT_friend:
break;
case InfoType::IT_default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -1018,6 +1019,8 @@ static std::string getRefType(InfoType IT) {
return "concept";
case InfoType::IT_variable:
return "variable";
+ case InfoType::IT_friend:
+ return "friend";
}
llvm_unreachable("Unknown InfoType");
}
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index c611c946b3937..7aeaa1b7cf67d 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -588,6 +588,7 @@ Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
case InfoType::IT_concept:
break;
case InfoType::IT_variable:
+ case InfoType::IT_friend:
break;
case InfoType::IT_default:
return createStringError(inconvertibleErrorCode(), "unexpected InfoType");
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 1f6167f7f9b8d..0e1a0cc347e45 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -39,8 +39,7 @@ static void serializeArray(const Container &Records, Object &Obj,
static auto SerializeInfoLambda = [](const auto &Info, Object &Object) {
serializeInfo(Info, Object);
};
-static auto SerializeReferenceLambda = [](const Reference &Ref,
- Object &Object) {
+static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) {
serializeReference(Ref, Object);
};
@@ -365,6 +364,22 @@ static void serializeInfo(const BaseRecordInfo &I, Object &Obj,
Obj["IsParent"] = I.IsParent;
}
+static void serializeInfo(const FriendInfo &I, Object &Obj) {
+ auto FriendRef = Object();
+ serializeReference(I.Ref, FriendRef);
+ Obj["Reference"] = std::move(FriendRef);
+ Obj["IsClass"] = I.IsClass;
+ if (I.Template)
+ serializeInfo(I.Template.value(), Obj);
+ if (I.Params)
+ serializeArray(I.Params.value(), Obj, "Params", SerializeInfoLambda);
+ if (I.ReturnType) {
+ auto ReturnTypeObj = Object();
+ serializeInfo(I.ReturnType.value(), ReturnTypeObj);
+ Obj["ReturnType"] = std::move(ReturnTypeObj);
+ }
+}
+
static void serializeInfo(const RecordInfo &I, json::Object &Obj,
const std::optional<StringRef> &RepositoryUrl) {
serializeCommonAttributes(I, Obj, RepositoryUrl);
@@ -436,6 +451,9 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj,
if (I.Template)
serializeInfo(I.Template.value(), Obj);
+ if (!I.Friends.empty())
+ serializeArray(I.Friends, Obj, "Friends", SerializeInfoLambda);
+
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
}
@@ -525,6 +543,7 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
case InfoType::IT_function:
case InfoType::IT_typedef:
case InfoType::IT_variable:
+ case InfoType::IT_friend:
break;
case InfoType::IT_default:
return createStringError(inconvertibleErrorCode(), "unexpected info type");
diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 608a7f6d4a9d3..6f16f5bd2f528 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -378,6 +378,9 @@ static llvm::Error genIndex(ClangDocContext &CDCtx) {
case InfoType::IT_variable:
Type = "Variable";
break;
+ case InfoType::IT_friend:
+ Type = "Friend";
+ break;
case InfoType::IT_default:
Type = "Other";
}
@@ -472,6 +475,7 @@ llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
break;
case InfoType::IT_concept:
case InfoType::IT_variable:
+ case InfoType::IT_friend:
break;
case InfoType::IT_default:
return createStringError(llvm::inconvertibleErrorCode(),
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 5b94d37d868b4..ba53329a41789 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -147,6 +147,8 @@ mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
return reduce<ConceptInfo>(Values);
case InfoType::IT_variable:
return reduce<VarInfo>(Values);
+ case InfoType::IT_friend:
+ return reduce<FriendInfo>(Values);
case InfoType::IT_default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"unexpected info type");
@@ -247,6 +249,15 @@ void Reference::merge(Reference &&Other) {
Path = Other.Path;
}
+bool FriendInfo::mergeable(const FriendInfo &Other) {
+ return Ref.USR == Other.Ref.USR && Ref.Name == Other.Ref.Name;
+}
+
+void FriendInfo::merge(FriendInfo &&Other) {
+ assert(mergeable(Other));
+ Ref.merge(std::move(Other.Ref));
+}
+
void Info::mergeBase(Info &&Other) {
assert(mergeable(Other));
if (USR == EmptySID)
@@ -313,6 +324,8 @@ void RecordInfo::merge(RecordInfo &&Other) {
Parents = std::move(Other.Parents);
if (VirtualParents.empty())
VirtualParents = std::move(Other.VirtualParents);
+ if (Friends.empty())
+ Friends = std::move(Other.Friends);
// Reduce children if necessary.
reduceChildren(Children.Records, std::move(Other.Children.Records));
reduceChildren(Children.Functions, std::move(Other.Children.Functions));
@@ -422,6 +435,9 @@ llvm::SmallString<16> Info::extractName() const {
case InfoType::IT_variable:
return llvm::SmallString<16>("@nonymous_variable_" +
toHex(llvm::toStringRef(USR)));
+ case InfoType::IT_friend:
+ return llvm::SmallString<16>("@nonymous_friend_" +
+ toHex(llvm::toStringRef(USR)));
case InfoType::IT_default:
return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR)));
}
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 59874f0cfcedf..fe5cc48069d58 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -46,7 +46,8 @@ enum class InfoType {
IT_enum,
IT_typedef,
IT_concept,
- IT_variable
+ IT_variable,
+ IT_friend
};
enum class CommentKind {
@@ -379,6 +380,22 @@ struct SymbolInfo : public Info {
bool IsStatic = false;
};
+struct FriendInfo : SymbolInfo {
+ FriendInfo() : SymbolInfo(InfoType::IT_friend) {}
+ FriendInfo(SymbolID USR) : SymbolInfo(InfoType::IT_friend, USR) {}
+ FriendInfo(const InfoType IT, const SymbolID &USR,
+ const StringRef Name = StringRef())
+ : SymbolInfo(IT, USR, Name) {}
+ bool mergeable(const FriendInfo &Other);
+ void merge(FriendInfo &&Other);
+
+ Reference Ref;
+ std::optional<TemplateInfo> Template;
+ std::optional<TypeInfo> ReturnType;
+ std::optional<SmallVector<FieldTypeInfo, 4>> Params;
+ bool IsClass = false;
+};
+
struct VarInfo : SymbolInfo {
VarInfo() : SymbolInfo(InfoType::IT_variable) {}
explicit VarInfo(SymbolID USR) : SymbolInfo(InfoType::IT_variable, USR) {}
@@ -454,6 +471,8 @@ struct RecordInfo : public SymbolInfo {
Bases; // List of base/parent records; this includes inherited methods and
// attributes
+ std::vector<FriendInfo> Friends;
+
ScopeChildren Children;
};
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 7a9cb8a1eddb9..12ef8891c720e 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -7,9 +7,12 @@
//===----------------------------------------------------------------------===//
#include "Serialize.h"
+#include "../clangd/CodeCompletionStrings.h"
#include "BitcodeWriter.h"
+
#include "clang/AST/Attr.h"
#include "clang/AST/Comment.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/StringExtras.h"
@@ -403,6 +406,7 @@ std::string serialize(std::unique_ptr<Info> &I) {
return serialize(*static_cast<ConceptInfo *>(I.get()));
case InfoType::IT_variable:
return serialize(*static_cast<VarInfo *>(I.get()));
+ case InfoType::IT_friend:
case InfoType::IT_typedef:
case InfoType::IT_default:
return "";
@@ -556,6 +560,7 @@ static std::unique_ptr<Info> makeAndInsertIntoParent(ChildType Child) {
case InfoType::IT_typedef:
case InfoType::IT_concept:
case InfoType::IT_variable:
+ case InfoType::IT_friend:
break;
}
llvm_unreachable("Invalid reference type for parent namespace");
@@ -947,6 +952,53 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
return {std::move(NSI), makeAndInsertIntoParent<const NamespaceInfo &>(*NSI)};
}
+static void parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
+ if (D->hasDefinition() && D->hasFriends())
+ for (const FriendDecl *FD : D->friends()) {
+ if (FD->isUnsupportedFriend())
+ continue;
+
+ FriendInfo F(InfoType::IT_friend, getUSRForDecl(FD));
+ const auto *ActualDecl = FD->getFriendDecl();
+ if (!ActualDecl) {
+ const auto *FriendTypeInfo = FD->getFriendType();
+ if (!FriendTypeInfo)
+ continue;
+ ActualDecl = FriendTypeInfo->getType()->getAsCXXRecordDecl();
+
+ if (!ActualDecl)
+ continue;
+ F.IsClass = true;
+ }
+
+ if (const auto *ActualTD = dyn_cast_or_null<TemplateDecl>(ActualDecl)) {
+ if (isa<RecordDecl>(ActualTD->getTemplatedDecl()))
+ F.IsClass = true;
+ F.Template.emplace();
+ for (const auto *Param : ActualTD->getTemplateParameters()->asArray())
+ F.Template->Params.emplace_back(
+ getSourceCode(Param, Param->getSourceRange()));
+ ActualDecl = ActualTD->getTemplatedDecl();
+ }
+
+ if (auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(ActualDecl)) {
+ FunctionInfo TempInfo;
+ parseParameters(TempInfo, FuncDecl);
+ F.Params.emplace();
+ F.Params = std::move(TempInfo.Params);
+ F.ReturnType = getTypeInfoForType(FuncDecl->getReturnType(),
+ FuncDecl->getLangOpts());
+ }
+
+ F.Ref = Reference(getUSRForDecl(ActualDecl),
+ ActualDecl->getNameAsString(), InfoType::IT_default,
+ ActualDecl->getQualifiedNameAsString(),
+ getInfoRelativePath(ActualDecl));
+
+ RI.Friends.push_back(std::move(F));
+ }
+}
+
std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
bool PublicOnly) {
@@ -970,6 +1022,7 @@ emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
// TODO: remove first call to parseBases, that function should be deleted
parseBases(*RI, C);
parseBases(*RI, C, /*IsFileInRootDir=*/true, PublicOnly, /*IsParent=*/true);
+ parseFriends(*RI, C);
}
RI->Path = getInfoRelativePath(RI->Namespace);
diff --git a/clang-tools-extra/cl...
[truncated]
|
8dd16ca
to
318f0c8
Compare
111fe87
to
41027d6
Compare
318f0c8
to
6a10b9c
Compare
Parse friends into a new FriendInfo and serialize them in JSON. We keep track of the friend declaration's template and function information if applicable.
Parse friends into a new FriendInfo and serialize them in JSON. We keep track of the friend declaration's template and function information if applicable.
Parse friends into a new FriendInfo and serialize them in JSON. We keep track of the friend declaration's template and function information if applicable.